package org.vaadin.nf4v.ext.config.util;

import org.vaadin.nf4v.core.config.ContextConfigurationException;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

/**
 * Utility methods for work with annotations.
 */
public class AnnotationUtil {

    /**
     * Searches for annotation in class and all it's super classes.
     *
     * @param ann   annotation to find
     * @param clazz class to search on
     * @return class annotation or null if not found
     */
    @SuppressWarnings("unchecked")
    public static <T extends Annotation> T getClassAnnotation(Class<T> ann, Class clazz) {
        Class tmpClazz = clazz;
        while (!tmpClazz.equals(Object.class)
                && !tmpClazz.getPackage().getName().startsWith("com.vaadin")
                && !tmpClazz.getPackage().getName().startsWith("java")) {
            if (tmpClazz.getAnnotation(ann) != null) {
                return (T) tmpClazz.getAnnotation(ann);
            }
            tmpClazz = clazz.getSuperclass();
        }
        return null;
    }

    /**
     * Searches annotated method in class and all it's super classes.
     *
     * @param ann   annotation to find
     * @param clazz class to search on
     * @return annotated method or null if not found
     * @throws ContextConfigurationException if more than one annotated method is found
     */
    public static <T extends Annotation> Method getAnnotatedMethod(Class<T> ann, Class clazz) throws ContextConfigurationException {
        Class tmpClazz = clazz;
        boolean found = false;
        Method result = null;
        while (!tmpClazz.equals(Object.class)
                && !tmpClazz.getPackage().getName().startsWith("com.vaadin")
                && !tmpClazz.getPackage().getName().startsWith("java")) {
            for (Method method : clazz.getDeclaredMethods()) {
                T methodAnn = method.getAnnotation(ann);
                if (methodAnn != null) {
                    if (found) {
                        throw new ContextConfigurationException("Duplicate method annotated with @" + ann.getSimpleName() +
                                " found in " + tmpClazz.getSimpleName() +
                                "#" + method.getName() + " for page class " + clazz.getSimpleName());
                    }
                    found = true;
                }
            }
            tmpClazz = clazz.getSuperclass();
        }
        return result;
    }

}
